// SPDX-License-Identifier: GPL-2.0
/*
 * imx581 driver
 *
 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
 *
 * V0.0X01.0X01 add poweron function.
 * V0.0X01.0X02 fix mclk issue when probe multiple camera.
 * V0.0X01.0X03 add enum_frame_interval function.
 */

#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/rk-camera-module.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
#include <linux/pinctrl/consumer.h>


#define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x05)

#ifndef V4L2_CID_DIGITAL_GAIN
#define V4L2_CID_DIGITAL_GAIN		V4L2_CID_GAIN
#endif

/*
V4L2_CID_LINK_FREQ
数据总线频率，与媒体总线爱你像素代码、总线类型一起定义喜爱你告诉阵列中的像素速率V4L2_CID_PIXEL_RATE
*/
// #define IMX581_LINK_FREQ_800MHZ	400000000LL
#define IMX581_LINK_FREQ_800MHZ	300000000LL
/*
V4L2_CID_PIXEL_RATE
像素速率
pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE
#define IMX581_PIXEL_RATE		(IMX581_LINK_FREQ_800MHZ * 2 * 4 / 10)
*/
// #define IMX581_PIXEL_RATE		(IMX581_LINK_FREQ_800MHZ * 2 * 4 / 10)   //331200000
#define IMX581_PIXEL_RATE		1000000000
#define IMX581_XVCLK_FREQ		24000000
#define IMX581_REG_SCCB_ID		0x300c
#define IMX581_VENDOR_I2C_ADDR		0x10

#define IMX581_REG_CTRL_MODE		0x0100
#define IMX581_MODE_SW_STANDBY		0x0
#define IMX581_MODE_STREAMING		BIT(0)

#define IMX581_REG_EXPOSURE		0x0202
#define	IMX581_EXPOSURE_MIN		4
#define	IMX581_EXPOSURE_STEP		1
#define IMX581_VTS_MAX			0xFFF8		// 0x0340 0x0341 <=65528 multiple of 8

#define IMX581_REG_GAIN_H		0x0204
#define IMX581_REG_GAIN_L		0x0205
#define IMX581_GAIN_H_MASK		0x3f
#define IMX581_GAIN_H_SHIFT		8
#define IMX581_GAIN_L_MASK		0xff
#define IMX581_GAIN_MIN		0x0
#define IMX581_GAIN_MAX		0x3C00
#define IMX581_GAIN_STEP		1
#define IMX581_GAIN_DEFAULT		0x00

#define IMX581_REG_TEST_PATTERN	0x0601
#define	IMX581_TEST_PATTERN_ENABLE	0x02
#define	IMX581_TEST_PATTERN_DISABLE	0x00

#define IMX581_REG_VTS			0x380e

#define REG_NULL			0xFFFF

#define IMX581_REG_VALUE_08BIT		1
#define IMX581_REG_VALUE_16BIT		2
#define IMX581_REG_VALUE_24BIT		3

#define IMX581_LANES			4
#define IMX581_BITS_PER_SAMPLE		10

#define IMX581_CHIP_REVISION_REG	0x302A
#define IMX581_R1A			0xb1
#define IMX581_R2A			0xb2

#define OF_CAMERA_PINCTRL_STATE_DEFAULT	"rockchip,camera_default"
#define OF_CAMERA_PINCTRL_STATE_SLEEP	"rockchip,camera_sleep"

#define IMX581_NAME			"imx581"

static DEFINE_MUTEX(imx581_power_mutex);
static int imx581_power_count;

//static const struct regval *imx581_global_regs;

 static const char * const imx581_supply_names[] = {
     "avdd",		/* Analog power */
     "dovdd",	/* Digital I/O power */
     "dvdd",		/* Digital core power */
 };


#define IMX581_NUM_SUPPLIES ARRAY_SIZE(imx581_supply_names)

struct regval {
    u16 addr;
    u8 val;
};

/*
模式结构体
*/
struct imx581_mode {
    u32 width;						// setting宽
    u32 height;						// setting高
    struct v4l2_fract max_fps;		// 帧率 = v4l2_fract.denominator / v4l2_fract.numerator
    u32 hts_def;
    u32 vts_def;
    u32 exp_def;
    const struct regval *reg_list;
};

struct imx581 {
    struct i2c_client	*client;
    struct clk		*xvclk;
    struct gpio_desc	*reset_gpio;
    struct gpio_desc	*pwdn_gpio;
    struct regulator_bulk_data supplies[IMX581_NUM_SUPPLIES];
    struct regulator	*avdd_regulator;	/* Analog power */
    struct regulator	*dovdd_regulator;	/* Digital I/O power */
    struct regulator	*dvdd_regulator;

    struct pinctrl		*pinctrl;
    struct pinctrl_state	*pins_default;
    struct pinctrl_state	*pins_sleep;

    struct v4l2_subdev	subdev;
    struct media_pad	pad;
    struct v4l2_ctrl_handler ctrl_handler;
    struct v4l2_ctrl	*exposure;
    struct v4l2_ctrl	*anal_gain;
    struct v4l2_ctrl	*digi_gain;
    struct v4l2_ctrl	*hblank;
    struct v4l2_ctrl	*vblank;
    struct v4l2_ctrl	*test_pattern;
    struct mutex		mutex;
    bool			streaming;
    bool			power_on;
    const struct imx581_mode *cur_mode;
    u32			module_index;
    const char		*module_facing;
    const char		*module_name;
    const char		*len_name;

    struct v4l2_ctrl *link_freq;
    struct v4l2_ctrl *pixel_rate;
};

static struct imx581 *imx581_master;

#define to_imx581(sd) container_of(sd, struct imx581, subdev)

/*
 * Xclk 24Mhz
 */
static const struct regval imx581_1920x1080_global_regs[]  = {
   {0x0136,0x18},
   {0x0137,0x00},
   {0x3C7E,0x02},
   {0x3C7F,0x09},
   {0x0111,0x02},
   {0x3702,0x1F},
   {0x3706,0x17},
   {0x3707,0x6F},
   {0x380C,0x00},
   {0x3C00,0x10},
   {0x3C01,0x10},
   {0x3C02,0x10},
   {0x3C03,0x10},
   {0x3C04,0x10},
   {0x3C05,0x01},
   {0x3C06,0x00},
   {0x3C07,0x00},
   {0x3C08,0x03},
   {0x3C09,0xFF},
   {0x3C0A,0x01},
   {0x3C0B,0x00},
   {0x3C0C,0x00},
   {0x3C0D,0x03},
   {0x3C0E,0xFF},
   {0x3C0F,0x20},
   {0x3F86,0x01},
   {0x3F88,0x00},
   {0x3F89,0x01},
   {0x3F8E,0x00},
   {0x3F8F,0x01},
   {0x4D14,0xA6},
   {0x4D29,0xB0},
   {0x4D45,0x74},
   {0x4D49,0x00},
   {0x4D53,0xB1},
   {0x4D55,0x00},
   {0x4D5C,0xA6},
   {0x4D71,0xB0},
   {0x4D7B,0x51},
   {0x4D8D,0x86},
   {0x4D91,0x00},
   {0x4D99,0x3C},
   {0x4D9B,0x17},
   {0x4D9D,0x00},
   {0x4DA4,0xA6},
   {0x4DB9,0xB0},
   {0x4DD5,0x72},
   {0x4DD9,0x00},
   {0x4DE3,0xF5},
   {0x4DE5,0x00},
   {0x4DEC,0xA6},
   {0x4E01,0xB0},
   {0x4E1D,0x4A},
   {0x4E2B,0x69},
   {0x4E2D,0x00},
   {0x4E34,0xA6},
   {0x4E49,0xB0},
   {0x4E65,0x49},
   {0x4E69,0x00},
   {0x4E73,0x7C},
   {0x4E75,0x00},
   {0x4E81,0x0D},
   {0x4E85,0x51},
   {0x4E87,0x82},
   {0x4E95,0xBF},
   {0x4E97,0x00},
   {0x5282,0x01},
   {0x5715,0x09},
   {0x5717,0x93},
   {0x5729,0x93},
   {0x572B,0x0A},
   {0x572D,0x0C},
   {0x572F,0x93},
   {0x578F,0x0D},
   {0x57BF,0x5C},
   {0x5855,0xA0},
   {0x5857,0x82},
   {0x585B,0x52},
   {0x585F,0x52},
   {0x5861,0x84},
   {0x5863,0x9E},
   {0x586F,0xA4},
   {0x5C49,0x59},
   {0x5C4A,0x01},
   {0x5C4B,0x9C},
   {0x5D0A,0x01},
   {0x5D0B,0x93},
   {0x5D28,0x01},
   {0x5D29,0x93},
   {0x5D4A,0x01},
   {0x5D4B,0x93},
   {0x5D68,0x01},
   {0x5D69,0x93},
   {0x646F,0x1E},
   {0x6607,0x1E},
   {0x6630,0x1E},
   {0x6659,0x1E},
   {0x6682,0x1E},
   {0x66AB,0x1E},
   {0x66D4,0x1E},
   {0x66FD,0x1E},
   {0x6726,0x1E},
   {0x674F,0x1E},
   {0x6778,0x1E},
   {0x6C1C,0x00},
   {0x6C1D,0x01},
   {0x6C1E,0x03},
   {0x6C1F,0x04},
   {0x6C5C,0x68},
   {0x6C5D,0x74},
   {0x6C5E,0x12},
   {0x6C60,0x95},
   {0x6C61,0x1B},
   {0x6C63,0x1E},
   {0x6C64,0x15},
   {0x6C65,0x03},
   {0x6C66,0x81},
   {0x6C67,0x85},
   {0x6C68,0x4A},
   {0x6C6A,0x08},
   {0x6C6B,0x06},
   {0x6C6C,0x49},
   {0x6C6D,0x20},
   {0x6C6E,0x99},
   {0x6C6F,0x13},
   {0x6C71,0x43},
   {0x6C72,0x62},
   {0x6C73,0x5E},
   {0x6C74,0x78},
   {0x6C76,0x74},
   {0x6C77,0xF9},
   {0x6C79,0xB0},
   {0x6C7A,0x54},
   {0x6C7B,0x8E},
   {0x6C7D,0x95},
   {0x6C7E,0x8B},
   {0x6C80,0x2E},
   {0x6C81,0x1D},
   {0x6C82,0x44},
   {0x6C83,0x81},
   {0x6C84,0x45},
   {0x6C85,0x62},
   {0x6C87,0x0C},
   {0x6C88,0x86},
   {0x6C89,0x51},
   {0x6C8A,0x20},
   {0x6C8B,0x89},
   {0x6C8C,0x19},
   {0x6C8E,0x45},
   {0x6C8F,0x02},
   {0x6C90,0xA2},
   {0x6C91,0x48},
   {0x6C92,0x1C},
   {0x6C94,0xB9},
   {0x6C96,0x60},
   {0x6C97,0x73},
   {0x6C98,0x02},
   {0x6C99,0x05},
   {0x6C9A,0x89},
   {0x6C9B,0x48},
   {0x6C9C,0xC4},
   {0x6C9D,0x1C},
   {0x6C9E,0x1C},
   {0x6C9F,0xC6},
   {0x6CA0,0x80},
   {0x6CA1,0xE5},
   {0x6CA2,0x56},
   {0x6CA4,0x07},
   {0x6CA5,0x85},
   {0x6CA6,0x30},
   {0x6CA7,0x60},
   {0x6CA8,0x81},
   {0x6CA9,0x15},
   {0x6CAB,0x43},
   {0x6CAC,0x62},
   {0x6CAD,0x58},
   {0x6CAE,0x48},
   {0x6CAF,0x22},
   {0x6CB0,0xA5},
   {0x6CB1,0xFC},
   {0x6CB2,0xD0},
   {0x6CB3,0x68},
   {0x6CB4,0x63},
   {0x6CB5,0x8A},
   {0x6CB6,0x05},
   {0x6CB7,0x09},
   {0x6CB8,0x4B},
   {0x6CBA,0x1E},
   {0x6CBB,0x18},
   {0x6CBC,0xE2},
   {0x6CBD,0x81},
   {0x6CBE,0x4A},
   {0x6CBF,0x56},
   {0x6CC1,0x08},
   {0x6CC2,0x06},
   {0x6CC3,0x38},
   {0x6CC4,0xE0},
   {0x6CC5,0x82},
   {0x6CC6,0x96},
   {0x6CC8,0x43},
   {0x6CC9,0x62},
   {0x6CCA,0x5A},
   {0x6CCB,0x28},
   {0x6CCC,0x22},
   {0x6CCD,0x75},
   {0x6CCE,0xF9},
   {0x6CD0,0x60},
   {0x6CD1,0x53},
   {0x6CD2,0x82},
   {0x6CD3,0x05},
   {0x6CD4,0x89},
   {0x6CD5,0x38},
   {0x6CD6,0xC4},
   {0x6CD7,0x1C},
   {0x6CD8,0x18},
   {0x6CD9,0xE3},
   {0x6CDA,0x80},
   {0x6CDB,0xE5},
   {0x6CDC,0x52},
   {0x6CDE,0x07},
   {0x6CDF,0x85},
   {0x6CE0,0x38},
   {0x6CE1,0xE0},
   {0x6CE2,0x81},
   {0x6CE3,0x15},
   {0x6CE5,0x43},
   {0x6CE6,0x62},
   {0x6CE7,0x5A},
   {0x6CE8,0x88},
   {0x6CE9,0x22},
   {0x6CEA,0xA5},
   {0x6CEB,0x69},
   {0x6CED,0x70},
   {0x6CEE,0x63},
   {0x6CEF,0x86},
   {0x6CF0,0x05},
   {0x6CF1,0x09},
   {0x6CF2,0x4B},
   {0x6CF4,0x1E},
   {0x6CF5,0x18},
   {0x6CF6,0xE2},
   {0x6CF7,0x81},
   {0x6CF8,0x6A},
   {0x6CF9,0x52},
   {0x6CFB,0x08},
   {0x6E47,0x01},
   {0x6F29,0x07},
   {0x6F2A,0x08},
   {0x7100,0x06},
   {0x7101,0x41},
   {0x7102,0x20},
   {0x7103,0x92},
   {0x7104,0x95},
   {0x7106,0x43},
   {0x7107,0x62},
   {0x7108,0x5A},
   {0x7109,0x88},
   {0x710A,0x22},
   {0x710B,0x75},
   {0x710C,0xB9},
   {0x710E,0x68},
   {0x710F,0x53},
   {0x7110,0x06},
   {0x7111,0x05},
   {0x7112,0x89},
   {0x7113,0x08},
   {0x7114,0x84},
   {0x7115,0x1E},
   {0x7116,0x1C},
   {0x7117,0xC2},
   {0x7118,0x80},
   {0x7119,0xE5},
   {0x711A,0x46},
   {0x711C,0x07},
   {0x711D,0x86},
   {0x711E,0x30},
   {0x711F,0xE0},
   {0x7120,0x61},
   {0x7121,0x11},
   {0x7123,0x43},
   {0x7124,0xA2},
   {0x7125,0x58},
   {0x7126,0x68},
   {0x7127,0x28},
   {0x7128,0x64},
   {0x7129,0xB9},
   {0x712B,0x68},
   {0x712C,0x53},
   {0x712D,0x06},
   {0x712E,0x04},
   {0x712F,0x89},
   {0x7130,0x0B},
   {0x7132,0x1E},
   {0x7133,0x1C},
   {0x7134,0xC2},
   {0x7135,0x81},
   {0x7136,0x65},
   {0x7137,0x46},
   {0x7139,0x08},
   {0x713A,0x86},
   {0x713B,0x38},
   {0x713C,0xE0},
   {0x713D,0xA1},
   {0x713E,0x12},
   {0x7140,0x43},
   {0x7141,0xA2},
   {0x7142,0x58},
   {0x7143,0x68},
   {0x7144,0x28},
   {0x7145,0x64},
   {0x7146,0xB9},
   {0x7148,0x70},
   {0x7149,0x63},
   {0x714A,0x0E},
   {0x714B,0x05},
   {0x714C,0x89},
   {0x714D,0x28},
   {0x714E,0x84},
   {0x714F,0x20},
   {0x7150,0x1C},
   {0x7151,0xE3},
   {0x7152,0x80},
   {0x7153,0xE5},
   {0x7154,0x4E},
   {0x7156,0x08},
   {0x7157,0x86},
   {0x7158,0x39},
   {0x7159,0x20},
   {0x715A,0x61},
   {0x715B,0x14},
   {0x715D,0x44},
   {0x715E,0x02},
   {0x715F,0x5A},
   {0x7160,0x78},
   {0x7161,0x1C},
   {0x7162,0xA5},
   {0x7163,0x79},
   {0x7165,0x80},
   {0x7166,0x63},
   {0x7167,0x8E},
   {0x7168,0x07},
   {0x7169,0x09},
   {0x716A,0x3B},
   {0x716C,0x22},
   {0x716D,0x18},
   {0x716E,0xE4},
   {0x716F,0x81},
   {0x7170,0xA5},
   {0x7171,0x52},
   {0x7173,0x09},
   {0x7174,0x86},
   {0x7175,0x41},
   {0x7176,0x60},
   {0x7177,0x72},
   {0x7178,0x14},
   {0x717E,0x1C},
   {0x7180,0x79},
   {0x7189,0xA2},
   {0x71C4,0xE4},
   {0x71C9,0xC9},
   {0x71CB,0x3B},
   {0x71CD,0x9D},
   {0x71CE,0x53},
   {0x71D0,0xC9},
   {0x71D2,0x1B},
   {0x71D4,0x9D},
   {0x71D5,0x63},
   {0x71D7,0xC9},
   {0x71D9,0xE2},
   {0x71DA,0x75},
   {0x71E7,0xDA},
   {0x71EC,0xDA},
   {0x895C,0x01},
   {0x895D,0x00},
   {0x8962,0x06},
   {0x8967,0x10},
   {0x896B,0x0D},
   {0x896F,0x25},
   {0x8976,0x00},
   {0x8977,0x00},
   {0x9004,0x14},
   {0x9200,0xF4},
   {0x9201,0xA7},
   {0x9202,0xF4},
   {0x9203,0xAA},
   {0x9204,0xF4},
   {0x9205,0xAD},
   {0x9206,0xF4},
   {0x9207,0xB0},
   {0x9208,0xF4},
   {0x9209,0xB3},
   {0x920A,0xB7},
   {0x920B,0x34},
   {0x920C,0xB7},
   {0x920D,0x36},
   {0x920E,0xB7},
   {0x920F,0x37},
   {0x9210,0xB7},
   {0x9211,0x38},
   {0x9212,0xB7},
   {0x9213,0x39},
   {0x9214,0xB7},
   {0x9215,0x3A},
   {0x9216,0xB7},
   {0x9217,0x3C},
   {0x9218,0xB7},
   {0x9219,0x3D},
   {0x921A,0xB7},
   {0x921B,0x3E},
   {0x921C,0xB7},
   {0x921D,0x3F},
   {0x921E,0x77},
   {0x921F,0x77},
   {0x9222,0xC4},
   {0x9223,0x4B},
   {0x9224,0xC4},
   {0x9225,0x4C},
   {0x9226,0xC4},
   {0x9227,0x4D},
   {0x9385,0xE6},
   {0x9387,0x55},
   {0x9389,0x55},
   {0x938B,0x55},
   {0x938D,0x50},
   {0x938F,0x3C},
   {0x9391,0x3C},
   {0x9393,0x32},
   {0x9395,0x26},
   {0x9397,0x26},
   {0x9399,0xA0},
   {0x939B,0x78},
   {0x939D,0x46},
   {0x939F,0x26},
   {0x93A1,0x26},
   {0x93A3,0xB4},
   {0x93A5,0x8C},
   {0x93A7,0x5A},
   {0x93A9,0x26},
   {0x93AB,0x26},
   {0x93AD,0xB4},
   {0x93AF,0x8C},
   {0x93B1,0x70},
   {0x93B3,0x26},
   {0x93B5,0x26},
   {0x93B7,0x64},
   {0x93B9,0x64},
   {0x93BB,0x50},
   {0x93BD,0x26},
   {0x93BF,0x26},
   {0x93C1,0x78},
   {0x93C3,0x78},
   {0x93C5,0x5A},
   {0x93C7,0x26},
   {0x93C9,0x26},
   {0x93CB,0x8C},
   {0x93CD,0x8C},
   {0x93CF,0x78},
   {0x93D1,0x26},
   {0x93D3,0x26},
   {0x93D5,0x78},
   {0x93D7,0x78},
   {0x93D9,0x5A},
   {0x93DB,0x26},
   {0x93DD,0x26},
   {0x93DF,0x50},
   {0x93E1,0x50},
   {0x93E3,0x50},
   {0x93E5,0x26},
   {0x93E7,0x26},
   {0x9810,0x14},
   {0x9814,0x14},
   {0x99B2,0x20},
   {0x99B3,0x0F},
   {0x99B4,0x0F},
   {0x99B5,0x0F},
   {0x99B6,0x0F},
   {0x99E4,0x0F},
   {0x99E5,0x0F},
   {0x99E6,0x0F},
   {0x99E7,0x0F},
   {0x99E8,0x0F},
   {0x99E9,0x0F},
   {0x99EA,0x0F},
   {0x99EB,0x0F},
   {0x99EC,0x0F},
   {0x99ED,0x0F},
   {0xA569,0x06},
   {0xA56A,0x13},
   {0xA56B,0x13},
   {0xA679,0x20},
   {0xA830,0x68},
   {0xA831,0x56},
   {0xA832,0x2B},
   {0xA833,0x55},
   {0xA834,0x55},
   {0xA835,0x16},
   {0xA837,0x51},
   {0xA838,0x34},
   {0xA854,0x4F},
   {0xA855,0x48},
   {0xA856,0x45},
   {0xA857,0x02},
   {0xA85A,0x23},
   {0xA85B,0x16},
   {0xA85C,0x12},
   {0xA85D,0x02},
   {0xAC72,0x01},
   {0xAC73,0x26},
   {0xAC74,0x01},
   {0xAC75,0x26},
   {0xAC76,0x00},
   {0xAC77,0xC4},
   {0xB051,0x02},
   {0xBC76,0x0F},
   {0xBC77,0x88},
   {0xBC79,0xA0},
   {0xBC7B,0x78},
   {0xBC7C,0x10},
   {0xBC7D,0xA0},
   {0xBC7F,0x30},
   {0xC020,0x01},
   {0xC027,0x00},
   {0xC13C,0x01},
   {0xC140,0x08},
   {0xC141,0x30},
   {0xC142,0x07},
   {0xC143,0x01},
   {0xC145,0x00},
   {0xC146,0x01},
   {0xC149,0x00},
   {0xC448,0x01},
   {0xC44B,0x05},
   {0xC44C,0x05},
   {0xC44D,0x2D},
   {0xC44F,0x01},
   {0xC451,0x00},
   {0xC452,0x01},
   {0xC455,0x00},
   {0xC61D,0x00},
   {0xC625,0x00},
   {0xC638,0x03},
   {0xC63B,0x01},
   {0xE286,0x31},
   {0xE2A6,0x32},
   {0xE2C6,0x33},
   {0xEA4B,0x00},
   {0xEA4C,0x00},
   {0xEA4D,0x00},
   {0xEA4E,0x00},
   {0xEC00,0x01},
   {0xF000,0x00},
   {0xF001,0x10},
   {0xF00C,0x00},
   {0xF00D,0x40},
   {0xF030,0x00},
   {0xF031,0x10},
   {0xF03C,0x00},
   {0xF03D,0x40},
   {0xF44B,0x80},
   {0xF44C,0x10},
   {0xF44D,0x06},
   {0xF44E,0x80},
   {0xF44F,0x10},
   {0xF450,0x06},
   {0xF451,0x80},
   {0xF452,0x10},
   {0xF453,0x06},
   {0xF454,0x80},
   {0xF455,0x10},
   {0xF456,0x06},
   {0xF457,0x80},
   {0xF458,0x10},
   {0xF459,0x06},
   {0xF478,0x20},
   {0xF479,0x80},
   {0xF47A,0x80},
   {0xF47B,0x20},
   {0xF47C,0x80},
   {0xF47D,0x80},
   {0xF47E,0x20},
   {0xF47F,0x80},
   {0xF480,0x80},
   {0xF481,0x20},
   {0xF482,0x60},
   {0xF483,0x80},
   {0xF484,0x20},
   {0xF485,0x60},
   {0xF486,0x80},
   {0x9852,0x00},
   {0x9954,0x0F},
   {0xA7AD,0x01},
   {0xA7CB,0x01},
   {0xAE09,0xFF},
   {0xAE0A,0xFF},
   {0xAE12,0x58},
   {0xAE13,0x58},
   {0xAE15,0x10},
   {0xAE16,0x10},
   {0xAF05,0x48},
   {0xB07C,0x02},
   {0x0112,0x0A},
   {0x0113,0x0A},
   {0x0114,0x03},         // 1lane:0x00  2lane:0x01 4lane:0x03
   {0x0342,0x1e},         // length of line 0x1ec0:7872
   {0x0343,0xc0},
   {0x0340,0x16},         // length of frame 0x16be:5822
   {0x0341,0xbe},
   {0x0344,0x00},
   {0x0345,0x00},
   {0x0346,0x00},
   {0x0347,0x00},
   {0x0348,0x1F},
   {0x0349,0x3F},
   {0x034A,0x17},
   {0x034B,0x6F},
   {0x0220,0x62},
   {0x0222,0x01},
   {0x0900,0x01},
   {0x0901,0x22},
   {0x0902,0x08},
   {0x3140,0x00},
   {0x3246,0x81},
   {0x3247,0x81},
   {0x3F15,0x00},
   {0x0401,0x00},
   {0x0404,0x00},
   {0x0405,0x10},
   {0x0408,0x00},     // X起始位置0
   {0x0409,0x00},
   {0x040A,0x00},     // Y起始位置0
   {0x040B,0x00},
   {0x040C,0x07},     // 图像宽0x0fa0:4000pixels               图像宽0x0780:1920pixels
   {0x040D,0x80},
   {0x040E,0x04},     // 图像高0x0bb8:3000pixels               图像高0x0438:1080pixels
   {0x040F,0x38},
   {0x034C,0x07},     // 输出图像宽0x0fa0:4000pixels            输出图像宽0x0fa0:1920pixels
   {0x034D,0x80},
   {0x034E,0x04},     // 输出图像高0x0bb8:3000pixels            输出图像高0x0bb8:1080pixels
   {0x034F,0x38},
   {0x0301,0x05},     // IVT_PCK_DIV:5
   {0x0303,0x02},     // IVT_SYCK_DIV:2
   {0x0305,0x04},     // IVT_PREPLLCK_DIV:4
   {0x0306,0x00},     // IVT_PLL_MPY[10:8]:191
   {0x0307,0xBF},     // IVT_PLL_MPY[7:0]
   {0x030B,0x02},     // IOP_SYCK_DIV:2
   {0x030D,0x03},     // IOP_PREPLLCK_DIV:3
   {0x030E,0x00},     // IOP_PLL_MPY[12:8]:200
   {0x030F,0xC8},     // IOP_PLL_MPY[8:0]
   {0x0310,0x01},
   {0x3620,0x00},
   {0x3621,0x00},
   {0x3C11,0x04},
   {0x3C12,0x03},
   {0x3C13,0x2D},
   {0x3F0C,0x01},
   {0x3F14,0x00},
   {0x3F80,0x01},
   {0x3F81,0x90},
   {0x3F8C,0x00},
   {0x3F8D,0x14},
   {0x3FF8,0x01},
   {0x3FF9,0x2A},
   {0x3FFE,0x00},
   {0x3FFF,0x6C},
   {0x0202,0x16},
   {0x0203,0x8E},
   {0x0224,0x01},
   {0x0225,0xF4},
   {0x3FE0,0x01},
   {0x3FE1,0xF4},
   {0x0204,0x00},
   {0x0205,0x70},
   {0x0216,0x00},
   {0x0217,0x70},
   {0x0218,0x01},
   {0x0219,0x00},
   {0x020E,0x01},
   {0x020F,0x00},
   {0x0210,0x01},
   {0x0211,0x00},
   {0x0212,0x01},
   {0x0213,0x00},
   {0x0214,0x01},
   {0x0215,0x00},
   {0x3FE2,0x00},
   {0x3FE3,0x70},
   {0x3FE4,0x01},
   {0x3FE5,0x00},
   {0x3E20,0x02},
   {0x3E3B,0x00},
   {0x4434,0x00},
   {0x4435,0xF8},


   {0x0b05,0x01},
   {0x0b06,0x01},
   {0xBCF1,0x00},//embed line
    { REG_NULL, 0x00 },



};




/* ----------支持的图像大小，帧率，以及该配置对应的setting----------*/
static const struct imx581_mode supported_modes[] = {
    {
        .width = 1920,
        .height = 1080,
        .max_fps = {
            .numerator = 10000,
            // .denominator = 200000,
            .denominator = 200000,
        },
        .exp_def = 0x0100,
        .hts_def = 0x12c0,	// V4L2_CID_HBLANK hblank = hts_def - width
        .vts_def = 0x0680,	// V4L2_CID_VBLANK vblank_def = vts_def - height
        .reg_list = imx581_1920x1080_global_regs,
    },
};

static const s64 link_freq_menu_items[] = {
    IMX581_LINK_FREQ_800MHZ
};

static const char * const imx581_test_pattern_menu[] = {
    "Disabled",
    "Color Bar Type 1",
    "Color Bar Type 2",
    "Color Bar Type 3",
    "Color Bar Type 4"
};

/* Write registers up to 4 at a time */
static int imx581_write_reg(struct i2c_client *client, u16 reg,
                 u32 len, u32 val)
{
    u32 buf_i, val_i;
    u8 buf[6];
    u8 *val_p;
    __be32 val_be;

    if (len > 4)
        return -EINVAL;

    buf[0] = reg >> 8;
    buf[1] = reg & 0xff;

    val_be = cpu_to_be32(val);
    val_p = (u8 *)&val_be;
    buf_i = 2;
    val_i = 4 - len;

    while (val_i < 4)
        buf[buf_i++] = val_p[val_i++];

    if (i2c_master_send(client, buf, len + 2) != len + 2)
        return -EIO;

    return 0;
}

static int imx581_write_array(struct i2c_client *client,
                   const struct regval *regs)
{
    u32 i;
    int ret = 0;

    for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
        ret = imx581_write_reg(client, regs[i].addr,
                    IMX581_REG_VALUE_08BIT,
                    regs[i].val);

    return ret;
}

/* Read registers up to 4 at a time */
static int imx581_read_reg(struct i2c_client *client, u16 reg,
                unsigned int len, u32 *val)
{
    struct i2c_msg msgs[2];
    u8 *data_be_p;
    __be32 data_be = 0;
    __be16 reg_addr_be = cpu_to_be16(reg);
    int ret;

    if (len > 4 || !len)
        return -EINVAL;

    data_be_p = (u8 *)&data_be;
    /* Write register address */
    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 2;
    msgs[0].buf = (u8 *)&reg_addr_be;

    /* Read data from register */
    msgs[1].addr = client->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = len;
    msgs[1].buf = &data_be_p[4 - len];

    ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
    if (ret != ARRAY_SIZE(msgs))
        return -EIO;

    *val = be32_to_cpu(data_be);

    return 0;
}

static int imx581_get_reso_dist(const struct imx581_mode *mode,
    struct v4l2_mbus_framefmt *framefmt)
{
    return abs(mode->width - framefmt->width) +
           abs(mode->height - framefmt->height);
}

static const struct imx581_mode *
    imx581_find_best_fit(struct v4l2_subdev_format *fmt)
{
    struct v4l2_mbus_framefmt *framefmt = &fmt->format;
    int dist;
    int cur_best_fit = 0;
    int cur_best_fit_dist = -1;
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
        dist = imx581_get_reso_dist(&supported_modes[i], framefmt);
        if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
            cur_best_fit_dist = dist;
            cur_best_fit = i;
        }
    }
    return &supported_modes[cur_best_fit];
}



static int imx581_set_fmt(struct v4l2_subdev *sd,
               struct v4l2_subdev_pad_config *cfg,
              struct v4l2_subdev_format *fmt)
{
    struct imx581 *imx581 = to_imx581(sd);
    const struct imx581_mode *mode;
    s64 h_blank, vblank_def;

    mutex_lock(&imx581->mutex);

    mode = imx581_find_best_fit(fmt);
    fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
    fmt->format.width = mode->width;
    fmt->format.height = mode->height;
    fmt->format.field = V4L2_FIELD_NONE;
    v4l2_info(sd,"/////////////////////////////////////////imx581_set_fmt()");
    v4l2_info(sd, "fmt: width:%d height:%d \n",(int)fmt->format.width,(int)fmt->format.height);
    v4l2_info(sd,"fmt->format.width = %d",fmt->format.width);
    v4l2_info(sd,"fmt->format.height = %d",fmt->format.height);
    v4l2_info(sd,"fmt->format.code = %d",fmt->format.code);
    v4l2_info(sd,"fmt->format.field = %d",fmt->format.field);
    v4l2_info(sd,"////////////////////////////////////////////////////////////////////////////////////////////////////////");
    if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
        *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
#else
        mutex_unlock(&imx581->mutex);
        return -ENOTTY;
#endif
    } else {
        imx581->cur_mode = mode;
        v4l2_info(sd, "cur_mode: width:%d height:%d \n",(int)mode->width,(int)mode->height);
        h_blank = mode->hts_def - mode->width;
        v4l2_info(sd, "h_blank: h_blank:%d \n",(int)h_blank);
        // 行消隐
        __v4l2_ctrl_modify_range(imx581->hblank, h_blank,
                     h_blank, 1, h_blank);
        v4l2_info(sd, "vblank_def: vblank_def:%d \n",(int)vblank_def);
        vblank_def = mode->vts_def - mode->height;
        v4l2_info(sd, "vblank_def: vblank_def:%d \n",(int)vblank_def);
        // 帧消隐
        __v4l2_ctrl_modify_range(imx581->vblank, vblank_def,
                     IMX581_VTS_MAX - mode->height,
                     1, vblank_def);
    }

    mutex_unlock(&imx581->mutex);

    return 0;
}

static int imx581_get_fmt(struct v4l2_subdev *sd,
               struct v4l2_subdev_pad_config *cfg,
               struct v4l2_subdev_format *fmt)
{
    struct imx581 *imx581 = to_imx581(sd);
    const struct imx581_mode *mode = imx581->cur_mode;

    mutex_lock(&imx581->mutex);
    if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
        fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
#else
        mutex_unlock(&imx581->mutex);
        return -ENOTTY;
#endif
    } else {
        fmt->format.width = mode->width;
        fmt->format.height = mode->height;
        fmt->format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
        fmt->format.field = V4L2_FIELD_NONE;
    }
    mutex_unlock(&imx581->mutex);
    v4l2_info(sd,"/////////////////////////////////////////imx581_get_fmt()");
    v4l2_info(sd, "fmt: width:%d height:%d \n",(int)fmt->format.width,(int)fmt->format.height);
    v4l2_info(sd,"fmt->format.width = %d",fmt->format.width);
    v4l2_info(sd,"fmt->format.height = %d",fmt->format.height);
    v4l2_info(sd,"fmt->format.code = %d",fmt->format.code);
    v4l2_info(sd,"fmt->format.field = %d",fmt->format.field);
    v4l2_info(sd,"////////////////////////////////////////////////////////////////////////////////////////////////////////");
    return 0;
}

static int imx581_enum_mbus_code(struct v4l2_subdev *sd,
                  struct v4l2_subdev_pad_config *cfg,
                  struct v4l2_subdev_mbus_code_enum *code)
{
    if (code->index != 0)
        return -EINVAL;
    code->code = MEDIA_BUS_FMT_SRGGB10_1X10;

    return 0;
}

static int imx581_enum_frame_sizes(struct v4l2_subdev *sd,
                    struct v4l2_subdev_pad_config *cfg,
                   struct v4l2_subdev_frame_size_enum *fse)
{
    if (fse->index >= ARRAY_SIZE(supported_modes))
        return -EINVAL;

    if (fse->code != MEDIA_BUS_FMT_SRGGB10_1X10)
        return -EINVAL;

    fse->min_width  = supported_modes[fse->index].width;
    fse->max_width  = supported_modes[fse->index].width;
    fse->max_height = supported_modes[fse->index].height;
    fse->min_height = supported_modes[fse->index].height;
    v4l2_info(sd,"/////////////////////////////////////////imx581_enum_frame_sizes()");
    v4l2_info(sd,"fse->min_width = %d",fse->min_width);
    v4l2_info(sd,"fse->max_width = %d",fse->max_width);
    v4l2_info(sd,"fse->max_height = %d",fse->max_height);
    v4l2_info(sd,"fse->min_height = %d",fse->min_height);
    v4l2_info(sd,"////////////////////////////////////////////////////////////////////////////////////////////////////////");

    return 0;
}

/*
parrent test
color bar
*/
static int imx581_enable_test_pattern(struct imx581 *imx581, u32 pattern)
{
    u32 val;

    if (pattern)
        val = (pattern - 1) | IMX581_TEST_PATTERN_ENABLE;
    else
        val = IMX581_TEST_PATTERN_DISABLE;

    return imx581_write_reg(imx581->client,
                 IMX581_REG_TEST_PATTERN,
                 IMX581_REG_VALUE_08BIT,
                 val);
}

static int imx581_g_frame_interval(struct v4l2_subdev *sd,
                    struct v4l2_subdev_frame_interval *fi)
{
    struct imx581 *imx581 = to_imx581(sd);
    const struct imx581_mode *mode = imx581->cur_mode;

    mutex_lock(&imx581->mutex);
    fi->interval = mode->max_fps;
    mutex_unlock(&imx581->mutex);

    return 0;
}

static void imx581_get_module_inf(struct imx581 *imx581,
                   struct rkmodule_inf *inf)
{
    memset(inf, 0, sizeof(*inf));
    strlcpy(inf->base.sensor, IMX581_NAME, sizeof(inf->base.sensor));
    strlcpy(inf->base.module, imx581->module_name,
        sizeof(inf->base.module));
    strlcpy(inf->base.lens, imx581->len_name, sizeof(inf->base.lens));
}

static long imx581_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
    struct imx581 *imx581 = to_imx581(sd);
    long ret = 0;
    v4l2_info(sd, "/////////////////////////////////////////int imx581_compat_ioctl()");
    switch (cmd) {
    case RKMODULE_GET_MODULE_INFO:
        imx581_get_module_inf(imx581, (struct rkmodule_inf *)arg);
        break;
    default:
        ret = -ENOIOCTLCMD;
        break;
    }

    return ret;
}

#ifdef CONFIG_COMPAT
static long imx581_compat_ioctl32(struct v4l2_subdev *sd,
                   unsigned int cmd, unsigned long arg)
{
    void __user *up = compat_ptr(arg);
    struct rkmodule_inf *inf;
    struct rkmodule_awb_cfg *cfg;
    long ret;
    v4l2_info(sd, "/////////////////////////////////////////int mx581_compat_ioctl32()");
    switch (cmd) {
    case RKMODULE_GET_MODULE_INFO:
        inf = kzalloc(sizeof(*inf), GFP_KERNEL);
        if (!inf) {
            ret = -ENOMEM;
            return ret;
        }

        ret = imx581_ioctl(sd, cmd, inf);
        if (!ret)
            ret = copy_to_user(up, inf, sizeof(*inf));
        kfree(inf);
        break;
    case RKMODULE_AWB_CFG:
        cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
        if (!cfg) {
            ret = -ENOMEM;
            return ret;
        }

        ret = copy_from_user(cfg, up, sizeof(*cfg));
        if (!ret)
            ret = imx581_ioctl(sd, cmd, cfg);
        kfree(cfg);
        break;
    default:
        ret = -ENOIOCTLCMD;
        break;
    }

    return ret;
}
#endif

 static int __imx581_start_stream(struct imx581 *imx581)
{
    int ret;

    ret = imx581_write_array(imx581->client, imx581->cur_mode->reg_list);
    if (ret)
        return ret;

     mutex_unlock(&imx581->mutex);
     // 将所有控件初始化为默认值
     // 这将无条件地调用所有控件的s_ctrl。实际上，这会将硬件初始化为默认控件值。建议您这样做，因为这可确保内部数据结构和硬件同步。
     ret = v4l2_ctrl_handler_setup(&imx581->ctrl_handler);
     mutex_lock(&imx581->mutex);
     if (ret)
         return ret;
    printk("fmt: width:%d height:%d \n",(int)imx581->cur_mode->width,(int)imx581->cur_mode->height);
    printk("fmt: hts_def:%d vts_def:%d \n",(int)imx581->cur_mode->hts_def,(int)imx581->cur_mode->vts_def);
    imx581_write_reg(imx581->client,0x0100,1,1);
    imx581_write_reg(imx581->client,0x0100,1,0);
    printk("/////////////////////////////////////////__imx581_start_stream(struct imx581 *imx581)");
//	return imx581_write_reg(imx581->client,0x0100,1,1);
    return imx581_write_reg(imx581->client,
                 IMX581_REG_CTRL_MODE,
                 IMX581_REG_VALUE_08BIT,
                 IMX581_MODE_STREAMING);
}

static int __imx581_stop_stream(struct imx581 *imx581)
{
    dev_info(&imx581->client->dev,"/////////////////////////////////////////__imx581_stop_stream(struct imx581 *imx581)");
    return imx581_write_reg(imx581->client,
                 IMX581_REG_CTRL_MODE,
                 IMX581_REG_VALUE_08BIT,
                 IMX581_MODE_SW_STANDBY);
}

static int imx581_s_stream(struct v4l2_subdev *sd, int on)
{
    struct imx581 *imx581 = to_imx581(sd);
    struct i2c_client *client = imx581->client;
    int ret = 0;

    mutex_lock(&imx581->mutex);
    on = !!on;
    if (on == imx581->streaming)
        goto unlock_and_return;

    if (on) {
        ret = pm_runtime_get_sync(&client->dev);
        if (ret < 0) {
            pm_runtime_put_noidle(&client->dev);
            goto unlock_and_return;
        }

        ret = __imx581_start_stream(imx581);
        if (ret) {
            v4l2_err(sd, "start stream failed while write regs\n");
            pm_runtime_put(&client->dev);
            goto unlock_and_return;
        }
    } else {
        __imx581_stop_stream(imx581);
        pm_runtime_put(&client->dev);
    }

    imx581->streaming = on;
    v4l2_info(sd, "/////////////////////////////////////////imx581_s_stream(struct v4l2_subdev *sd, int on)");
unlock_and_return:
    mutex_unlock(&imx581->mutex);

    return ret;
}

static int imx581_s_power(struct v4l2_subdev *sd, int on)
{
    struct imx581 *imx581 = to_imx581(sd);
    struct i2c_client *client = imx581->client;
    int ret = 0;

    mutex_lock(&imx581->mutex);

    /* If the power state is not modified - no work to do. */
    if (imx581->power_on == !!on)
        goto unlock_and_return;

    if (on) {
        ret = pm_runtime_get_sync(&client->dev);
        if (ret < 0) {
            pm_runtime_put_noidle(&client->dev);
            goto unlock_and_return;
        }

        ret = imx581_write_array(imx581->client, imx581_1920x1080_global_regs);
        //ret = imx581_write_array(imx581->client, imx581_1920x1080_global_regs);
        // ret = imx581_write_array(imx581->client, imx581->cur_mode->reg_list);
        if (ret) {
            v4l2_err(sd, "could not set init registers I2Cwrite fail\n");
            pm_runtime_put_noidle(&client->dev);
            goto unlock_and_return;
        }

        imx581->power_on = true;
    } else {
        pm_runtime_put(&client->dev);
        imx581->power_on = false;
    }
    __imx581_stop_stream(imx581);
unlock_and_return:
    mutex_unlock(&imx581->mutex);

    return ret;
}

/* Calculate the delay in us by clock rate and clock cycles */
static inline u32 imx581_cal_delay(u32 cycles)
{
    return DIV_ROUND_UP(cycles, IMX581_XVCLK_FREQ / 1000 / 1000);
}

static int __imx581_master_power_on(struct device *dev) {
    struct imx581 *imx581 = imx581_master;
    int ret;

    if (!imx581) {
        dev_err(dev, "no imx581 master set\n");
        return -EINVAL;
    }

    //启动mclk
    ret = clk_set_rate(imx581->xvclk, IMX581_XVCLK_FREQ);
    if (ret < 0)
        dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
    if (clk_get_rate(imx581->xvclk) != IMX581_XVCLK_FREQ)
        dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
    ret = clk_prepare_enable(imx581->xvclk);
    if (ret < 0) {
        dev_err(dev, "Failed to enable xvclk\n");
        goto err_clk;
    }
    if (!IS_ERR_OR_NULL(imx581->pins_default)) {
        ret = pinctrl_select_state(imx581->pinctrl,
                       imx581->pins_default);
        if (ret < 0) {
            dev_err(dev, "could not set pins\n");
            goto err_pins;
        }
    }


     ret = regulator_bulk_enable(IMX581_NUM_SUPPLIES, imx581->supplies);
    if (ret < 0) {
        dev_err(dev, "Failed to enable regulators\n");
        goto err_regulator;
    }
    //pwdn启动
    if (!IS_ERR(imx581->pwdn_gpio))
        gpiod_set_value_cansleep(imx581->pwdn_gpio, 1);
    else{

        dev_err(dev,"there is not a pwdn_gpio in devicetree!!!!");
        return -1;
    }

    usleep_range(1100, 1200);

    //reset启动
    if (!IS_ERR(imx581->reset_gpio))
        gpiod_set_value_cansleep(imx581->reset_gpio, 1);
    else{
        dev_err(dev,"there is not a reset_gpio in devicetree!!!!");
        return -1;
    }
    dev_info(&imx581->client->dev,"/////////////////////////////////////////__imx581_master_power_on(struct device *dev)");
    return 1;
err_regulator:
    clk_disable_unprepare(imx581->xvclk);
err_clk:
    if (!IS_ERR_OR_NULL(imx581->pins_sleep)) {
        int _ret;
        _ret = pinctrl_select_state(imx581->pinctrl,
                       imx581->pins_sleep);
        if (ret < 0)
            dev_dbg(dev, "could not set sleep pins\n");
    }
err_pins:
    imx581_power_count--;

    return ret;
}

static void __imx581_master_power_off(struct device *dev)
{
    struct imx581 *imx581 = imx581_master;
    int ret;

    if (!imx581) {
        dev_err(dev, "no imx581 master set\n");
        return;
    }

    imx581_power_count--;
    if (imx581_power_count > 0) {
        return;
    }

    imx581_power_count--;
    if (imx581_power_count > 0) {
        return;
    }

    clk_disable_unprepare(imx581->xvclk);

    if (!IS_ERR(imx581->reset_gpio))
        gpiod_set_value_cansleep(imx581->reset_gpio, 0);
    if (!IS_ERR_OR_NULL(imx581->pins_sleep)) {
        ret = pinctrl_select_state(imx581->pinctrl,
                       imx581->pins_sleep);
        if (ret < 0)
            dev_dbg(dev, "could not set pins\n");
    }
    regulator_bulk_disable(IMX581_NUM_SUPPLIES, imx581->supplies);

    return;
}

static int __imx581_power_on(struct imx581 *imx581)
{
    int ret;
    struct device *dev = &imx581->client->dev;

    mutex_lock(&imx581_power_mutex);
    ret = __imx581_master_power_on(dev);
    if (!ret) {
        dev_err(dev, "could not power on, error %d\n", ret);
        goto err_power;
    }
    else{
        dev_info(dev, "__imx581_power_on is succeessful %d\n", ret);
    }

    usleep_range(10000, 11000);


    mutex_unlock(&imx581_power_mutex);
    dev_info(&imx581->client->dev,"/////////////////////////////////////////__imx581_power_on(struct imx581 *imx581)");
    return 0;


err_power:
    mutex_unlock(&imx581_power_mutex);
    return ret;
}

static void __imx581_power_off(struct imx581 *imx581)
{
    struct device *dev = &imx581->client->dev;

    mutex_lock(&imx581_power_mutex);
if(1){
    if (!IS_ERR(imx581->pwdn_gpio))
        gpiod_set_value_cansleep(imx581->pwdn_gpio, 0);
    __imx581_master_power_off(dev);
}
    mutex_unlock(&imx581_power_mutex);
    dev_info(&imx581->client->dev,"/////////////////////////////////////////__imx581_power_off(struct imx581 *imx581)");

}

static int imx581_runtime_resume(struct device *dev)
{
    struct i2c_client *client = to_i2c_client(dev);
    struct v4l2_subdev *sd = i2c_get_clientdata(client);
    struct imx581 *imx581 = to_imx581(sd);
    dev_info(&imx581->client->dev,"/////////////////////////////////////////imx581_runtime_resume(struct device *dev)");
    return __imx581_power_on(imx581);
}

static int imx581_runtime_suspend(struct device *dev)
{
    struct i2c_client *client = to_i2c_client(dev);
    struct v4l2_subdev *sd = i2c_get_clientdata(client);
    struct imx581 *imx581 = to_imx581(sd);

    __imx581_power_off(imx581);
    dev_info(&imx581->client->dev,"/////////////////////////////////////////imx581_runtime_suspend(struct device *dev)");
    return 0;
}

#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static int imx581_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
    struct imx581 *imx581 = to_imx581(sd);
    struct v4l2_mbus_framefmt *try_fmt =
                v4l2_subdev_get_try_format(sd, fh->pad, 0);
    const struct imx581_mode *def_mode = &supported_modes[0];

    mutex_lock(&imx581->mutex);
    /* Initialize try_fmt */
    try_fmt->width = def_mode->width;
    try_fmt->height = def_mode->height;
    try_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
    try_fmt->field = V4L2_FIELD_NONE;

    mutex_unlock(&imx581->mutex);
    /* No crop or compose */
    dev_info(&imx581->client->dev,"/////////////////////////////////////////imx581_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)");
    dev_info(&imx581->client->dev,"try_fmt->width = %d",try_fmt->width);
    dev_info(&imx581->client->dev,"try_fmt->height = %d",try_fmt->height);
    dev_info(&imx581->client->dev,"try_fmt->code = %d",try_fmt->code);
    dev_info(&imx581->client->dev,"try_fmt->field = %d",try_fmt->field);
    dev_info(&imx581->client->dev,"////////////////////////////////////////////////////////////////////////////////////////////////////////");
    return 0;
}
#endif

static int imx581_enum_frame_interval(struct v4l2_subdev *sd,
                       struct v4l2_subdev_pad_config *cfg,
                       struct v4l2_subdev_frame_interval_enum *fie)
{
    if (fie->index >= ARRAY_SIZE(supported_modes))
        return -EINVAL;

    if (fie->code != MEDIA_BUS_FMT_SRGGB10_1X10)
        return -EINVAL;

    fie->width = supported_modes[fie->index].width;
    fie->height = supported_modes[fie->index].height;
    fie->interval = supported_modes[fie->index].max_fps;

    v4l2_info(sd, "/////////////////////////////////////////int imx581_enum_frame_interval()");
    v4l2_info(sd, "fie->width = %d",fie->width);
    v4l2_info(sd, "fie->height = %d",fie->height);
    //v4l2_info(sd, "fie->interval = %d",fie->interval);
    v4l2_info(sd, "/////////////////////////////////////////////////////////////////////////");
    return 0;
}

static const struct dev_pm_ops imx581_pm_ops = {
    SET_RUNTIME_PM_OPS(imx581_runtime_suspend,
               imx581_runtime_resume, NULL)
};

#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
static const struct v4l2_subdev_internal_ops imx581_internal_ops = {
    .open = imx581_open,        //called when the subdev device node is opened by an application.
};
#endif

static const struct v4l2_subdev_core_ops imx581_core_ops = {
    .s_power = imx581_s_power,
    .ioctl = imx581_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl32 = imx581_compat_ioctl32,
#endif
};

static const struct v4l2_subdev_video_ops imx581_video_ops = {
    .s_stream = imx581_s_stream,
    .g_frame_interval = imx581_g_frame_interval,
};

static const struct v4l2_subdev_pad_ops imx581_pad_ops = {
    .enum_mbus_code = imx581_enum_mbus_code,
    .enum_frame_size = imx581_enum_frame_sizes,
    .enum_frame_interval = imx581_enum_frame_interval,
    .get_fmt = imx581_get_fmt,
    .set_fmt = imx581_set_fmt,
};

static const struct v4l2_subdev_ops imx581_subdev_ops = {
    .core	= &imx581_core_ops,
    .video	= &imx581_video_ops,
    .pad	= &imx581_pad_ops,
};

static int imx581_set_ctrl(struct v4l2_ctrl *ctrl)
{
    struct imx581 *imx581 = container_of(ctrl->handler,
                         struct imx581, ctrl_handler);
    struct i2c_client *client = imx581->client;

    int ret = 0;
    s64 max;

    /* Propagate change of current control to all related controls */
    switch (ctrl->id) {
    case V4L2_CID_VBLANK:
        /* Update max exposure while meeting expected vblanking */

        max = imx581->cur_mode->height + ctrl->val - 4;
        __v4l2_ctrl_modify_range(imx581->exposure,
                     imx581->exposure->minimum, max,
                     imx581->exposure->step,
                     imx581->exposure->default_value);
        dev_info(&client->dev, "%s V4L2_CID_VBLANK exp range default exposure:0x%x\n",
             __func__ ,(int)imx581->exposure->default_value);
        break;
    }

    if (pm_runtime_get(&client->dev) <= 0)
        return 0;

    switch (ctrl->id) {
    case V4L2_CID_EXPOSURE:
        /* 4 least significant bits of expsoure are fractional part */
        ret = imx581_write_reg(imx581->client,
                    IMX581_REG_EXPOSURE,
                    IMX581_REG_VALUE_16BIT,
                    ctrl->val<<4);
        dev_info(&client->dev, "%s V4L2_CID_EXPOSURE exposure:0x%x\n",
             __func__, ctrl->val);
        break;
    case V4L2_CID_ANALOGUE_GAIN:
    /*
    0x0204:ANA_GAIN_GLOBAL[13:8]
    0x0205:ANA_GAIN_GLOBAL[ 7:0]
    Analog gain = 16384/(16384-ANA_GAIN_GLOBAL)
    根据全像素和binning会有不同的gain值{0-15360或0-15872}，我们选小的作为公共的gain值，该值范围是{0-15360}
    */
        ret = imx581_write_reg(imx581->client,
                    IMX581_REG_GAIN_H,
                    IMX581_REG_VALUE_08BIT,
                    (ctrl->val >> IMX581_GAIN_H_SHIFT) &
                    IMX581_GAIN_H_MASK);
        ret |= imx581_write_reg(imx581->client,
                     IMX581_REG_GAIN_L,
                     IMX581_REG_VALUE_08BIT,
                     ctrl->val & IMX581_GAIN_L_MASK);
        dev_warn(&client->dev, "%s IMX581_REG_GAIN %d\n",
             __func__, ctrl->val);
        break;
    case V4L2_CID_VBLANK:
        ret = imx581_write_reg(imx581->client,
                    IMX581_REG_VTS,
                    IMX581_REG_VALUE_16BIT,
                    ctrl->val + imx581->cur_mode->height);
        dev_warn(&client->dev, "%s V4L2_CID_ANALOGUE_GAIN %d\n",
             __func__, 16384/(16384-ctrl->val));
        break;
    case V4L2_CID_TEST_PATTERN:
        // v4l2-ctl -d /dev/video0 --set-ctrl test_pattern=0
        ret = imx581_enable_test_pattern(imx581, ctrl->val);
        dev_warn(&client->dev, "%s imx581_enable_test_pattern %d\n",
             __func__, ctrl->val);
        break;
    default:
        dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
             __func__, ctrl->id, ctrl->val);
        break;
    }

    pm_runtime_put(&client->dev);

    return ret;
}

static const struct v4l2_ctrl_ops imx581_ctrl_ops = {
    .s_ctrl = imx581_set_ctrl,
};

static int imx581_initialize_controls(struct imx581 *imx581)
{
    const struct imx581_mode *mode;
    struct v4l2_ctrl_handler *handler;
    struct v4l2_ctrl *ctrl;
    s64 exposure_max, vblank_def;
    u32 h_blank;
    int ret;

    handler = &imx581->ctrl_handler;
    mode = imx581->cur_mode;
    ret = v4l2_ctrl_handler_init(handler, 8);
    if (ret)
        return ret;
    else
        dev_info(&imx581->client->dev,"--------the v4l2_ctrl_handler_init() is succeessful----------");


    handler->lock = &imx581->mutex;

    // 添加整数菜单控件
    ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
                      0, 0, link_freq_menu_items);
    if (ctrl)
        ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
    else{
        dev_info(&imx581->client->dev,"--------the ctrl of freq is fialed----------");return 1;
    }
    // 添加非菜单控件
    // v4l2_ctrl_new_std 函数返回指向新控件的 v4l2_ctrl 指针，但如果不需要在控件操作之外访问指针，则无需存储它。
    v4l2_ctrl_new_std(handler, 				/**/
                      NULL, 				/**/
                      V4L2_CID_PIXEL_RATE,	/*控件ID*/
                      0, 					/*最小值*/
                      IMX581_PIXEL_RATE, 	/*最大值*/
                      1, 					/*步长*/
                      IMX581_PIXEL_RATE);	/*默认值*/

    h_blank = mode->hts_def - mode->width;
    imx581->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
                h_blank, h_blank, 1, h_blank);
    if (imx581->hblank)
        imx581->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
    else{
        dev_info(&imx581->client->dev,"--------the imx581->hblank is failed----------");return 1;
    }
    vblank_def =  mode->vts_def - mode->height;
    dev_info(&imx581->client->dev,"vts_def:%d height:%d  \n",(int)mode->vts_def,(int)mode->height);
    dev_info(&imx581->client->dev,"h_blank:%d vblank_def:%d  \n",(int)h_blank,(int)vblank_def);
    imx581->vblank = v4l2_ctrl_new_std(handler, &imx581_ctrl_ops,
                V4L2_CID_VBLANK, vblank_def,
                IMX581_VTS_MAX - mode->height,
                1, vblank_def);
    if(!imx581->vblank){
        dev_info(&imx581->client->dev,"--------the imx581->vblank is failed----------");return 1;}

    exposure_max = mode->vts_def - 4;
    imx581->exposure = v4l2_ctrl_new_std(handler, &imx581_ctrl_ops,
                V4L2_CID_EXPOSURE, IMX581_EXPOSURE_MIN,
                exposure_max, IMX581_EXPOSURE_STEP,
                mode->exp_def);
    if(!imx581->exposure){
        dev_info(&imx581->client->dev,"--------the imx581->exposure is failed----------");return 1;}


    imx581->anal_gain = v4l2_ctrl_new_std(handler, &imx581_ctrl_ops,
                V4L2_CID_ANALOGUE_GAIN, IMX581_GAIN_MIN,
                IMX581_GAIN_MAX, IMX581_GAIN_STEP,
                IMX581_GAIN_DEFAULT);
    if(!imx581->anal_gain){
        dev_info(&imx581->client->dev,"--------the imx581->anal_gain is failed----------");return 1;}

    imx581->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
                &imx581_ctrl_ops, V4L2_CID_TEST_PATTERN,
                ARRAY_SIZE(imx581_test_pattern_menu) - 1,
                0, 0, imx581_test_pattern_menu);
    if(!imx581->test_pattern){
        dev_info(&imx581->client->dev,"--------the imx581->test_pattern is failed----------");return 1;
    }

    if (handler->error) {
        ret = handler->error;
        dev_err(&imx581->client->dev,
            "Failed to init controls(%d)\n", ret);
        goto err_free_handler;
    }
    imx581->subdev.ctrl_handler = handler;

    return 0;

err_free_handler:
    v4l2_ctrl_handler_free(handler);

    return ret;
}

#define CHIP_ID1					0x0581
#define IMX581_REG_CHIP_ID		0x0016

static int imx581_check_sensor_id(struct imx581 *imx581,
                   struct i2c_client *client)
{
    int ret;
    struct device *dev = &imx581->client->dev;
    u32 id = 0;

    ret = imx581_read_reg(client, IMX581_REG_CHIP_ID,
                   IMX581_REG_VALUE_16BIT, &id);
    if (id != CHIP_ID1) {
        dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
        return -ENODEV;
    }
    dev_info(dev,"----------check sensor id ok----------\r\n");


    return 0;
}

static int imx581_configure_regulators(struct imx581 *imx581)
{
    unsigned int i;

    for (i = 0; i < IMX581_NUM_SUPPLIES; i++)
        imx581->supplies[i].supply = imx581_supply_names[i];

    return devm_regulator_bulk_get(&imx581->client->dev,
                       IMX581_NUM_SUPPLIES,
                       imx581->supplies);
}

static void imx581_detach_master(void *data)
{
    if (imx581_master == data)
        imx581_master = NULL;
}

static int imx581_probe(struct i2c_client *client,
             const struct i2c_device_id *id)
{
    struct device *dev = &client->dev;
    struct device_node *node = dev->of_node;
    struct imx581 *imx581;
    struct v4l2_subdev *sd;
    char facing[2];
    int ret;

    dev_info(dev, "driver version: %02x.%02x.%02x",
        DRIVER_VERSION >> 16,
        (DRIVER_VERSION & 0xff00) >> 8,
        DRIVER_VERSION & 0x00ff);

    // 给设备结构体分配内存空间
    imx581 = devm_kzalloc(dev, sizeof(*imx581), GFP_KERNEL);
    if (!imx581)
        return -ENOMEM;
    // 从设备树获取属性：
    // 		"rockchip,camera-module-index"
    // 		"rockchip,camera-module-facing"
    // 		"rockchip,camera-module-name"
    // 		"rockchip,camera-module-lens-name"
    dev_info(dev, "===========================================================从设备树获取属性");
    ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
                   &imx581->module_index);
    ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
                       &imx581->module_facing);
    ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
                       &imx581->module_name);
    ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
                       &imx581->len_name);
    if (ret) {
        dev_err(dev, "could not get module information!\n");
        return -EINVAL;
    }
    // iic client
    imx581->client = client;
    // 保存支持的图像格式
    imx581->cur_mode = &supported_modes[0];

    if (!imx581_master) {
        imx581_master = imx581;
        devm_add_action(dev, imx581_detach_master, imx581);
    }
    if (imx581_master == imx581) {
        // 获取时钟 xvclk
        dev_info(dev, "===========================================================获取时钟 获取时钟 xvclk");
        imx581->xvclk = devm_clk_get(dev, "xvclk");
        if (IS_ERR(imx581->xvclk)) {
            dev_err(dev, "Failed to get xvclk\n");
            return -EINVAL;
        }
        // 获取reset引脚
        dev_info(dev, "===========================================================获取reset引脚");
        imx581->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
        if (IS_ERR(imx581->reset_gpio))
            dev_warn(dev, "Failed to get reset-gpios\n");
        // pinctrl 获取
        imx581->pinctrl = devm_pinctrl_get(dev);
        if (!IS_ERR(imx581->pinctrl)) {
            imx581->pins_default =
                pinctrl_lookup_state(imx581->pinctrl,
                             OF_CAMERA_PINCTRL_STATE_DEFAULT);
            if (IS_ERR(imx581->pins_default))
                dev_err(dev, "could not get default pinstate\n");

            imx581->pins_sleep =
                pinctrl_lookup_state(imx581->pinctrl,
                             OF_CAMERA_PINCTRL_STATE_SLEEP);
            if (IS_ERR(imx581->pins_sleep))
                dev_err(dev, "could not get sleep pinstate\n");
        }
    }
    // 获取pwdn引脚
    dev_info(dev, "===========================================================获取pwdn引脚");
    imx581->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
    if (IS_ERR(imx581->pwdn_gpio))
        dev_warn(dev, "Failed to get pwdn-gpios\n");

     // 获取电源
     dev_info(dev, "===========================================================获取电源");
     ret = imx581_configure_regulators(imx581);
     if (ret) {
        dev_err(dev, "Failed to get power regulators\n");
        return ret;
     }



    mutex_init(&imx581->mutex);

    sd = &imx581->subdev;
    // iic 子设备初始化
    dev_info(dev, "===========================================================iic 子设备初始化");
    // 3、将当前IIC client作为v4l2的一个IIC子设备。
    /*该函数定义在v4l2-common.c中
    *	void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
    *		const struct v4l2_subdev_ops *ops)
    *	{
    *		v4l2_subdev_init(sd, ops);									// 初始化一个v4l2-subdev对象			
    *		sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
    *		// the owner is the same as the i2c_client's driver owner
    *		sd->owner = client->dev.driver->owner;
    *		sd->dev = &client->dev;
    *		// i2c_client and v4l2_subdev point to one another 
    *		v4l2_set_subdevdata(sd, client);
    *		i2c_set_clientdata(client, sd);
    *		// initialize name
    *		snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
    *			client->dev.driver->name, i2c_adapter_id(client->adapter),
    *			client->addr);
    *	}
    *	该v4l2-subdev的ops:
    *	static const struct v4l2_subdev_ops imx581_subdev_ops = {
    *		.core	= &imx581_core_ops,         //Define core ops callbacks for subdevs
    *		.video	= &imx581_video_ops,        //Callbacks used when v4l device was opened in video mode.
    *		.pad	= &imx581_pad_ops,          //v4l2-subdev pad level operations
    *	};
    *          static const struct v4l2_subdev_core_ops imx581_core_ops = {
    *              .s_power = imx581_s_power,                          //puts subdevice in power saving mode (on == 0) or normal operation mode (on == 1).
    *              .ioctl = imx581_ioctl,                              //called at the end of ioctl() syscall handler at the V4L2 core. used to provide support for private ioctls used on the driver.
    *          #ifdef CONFIG_COMPAT
    *              .compat_ioctl32 = imx581_compat_ioctl32,            //called when a 32 bits application uses a 64 bits Kernel, in order to fix data passed from/to userspace.
    *          #endif
    *          };
    *        
    *          static const struct v4l2_subdev_video_ops imx581_video_ops = {
    *              .s_stream = imx581_s_stream,                        // used to notify the driver that a video stream will start or has stopped.
    *              .g_frame_interval = imx581_g_frame_interval,        // callback for VIDIOC_G_FRAMEINTERVAL ioctl handler code.
    *          };
    *        
    *          static const struct v4l2_subdev_pad_ops imx581_pad_ops = {
    *              .enum_mbus_code = imx581_enum_mbus_code,            //callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler code.
    *              .enum_frame_size = imx581_enum_frame_sizes,         //callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler code.
    *              .enum_frame_interval = imx581_enum_frame_interval,  //callback for VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL ioctl
    *              .get_fmt = imx581_get_fmt,                          //callback for VIDIOC_SUBDEV_G_FMT ioctl handler code.
    *              .set_fmt = imx581_set_fmt,                          //callback for VIDIOC_SUBDEV_S_FMT ioctl handler code.
    *          };
    */
    v4l2_i2c_subdev_init(sd, client, &imx581_subdev_ops);
    // v4l2 controller 初始化
    dev_info(dev, "===========================================================v4l2 controller 初始化");
    ret = imx581_initialize_controls(imx581);
    if (ret)
        goto err_destroy_mutex;
    
    dev_info(dev, "===========================================================上电");
    // sensor 上电，各引脚的上电顺序及时间间隔应符合sensor datasheet中的上电时序。（目前大部分sensor的上电时序并无严格要求。）
    ret = __imx581_power_on(imx581);
    if (ret)
        goto err_free_handler;
    
    dev_info(dev, "===========================================================check sensor id");
    // check sensor id，通过IIC读取sensor的who am i寄存器，来判断IIC是否能够正常工作，只有sensor上电成功后IIC才可以正常工作。
     ret = imx581_check_sensor_id(imx581, client);
     if (ret)
        goto err_power_off;

#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
    // Internal ops. Never call this from drivers, only the v4l2 framework can call these ops.
    // open: called when the subdev device node is opened by an application.
    sd->internal_ops = &imx581_internal_ops;
    sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
    imx581->pad.flags = MEDIA_PAD_FL_SOURCE;
    sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
    ret = media_entity_init(&sd->entity, 1, &imx581->pad, 0);
    if (ret < 0)
        goto err_power_off;
#endif

    memset(facing, 0, sizeof(facing));
    if (strcmp(imx581->module_facing, "back") == 0)
        facing[0] = 'b';
    else
        facing[0] = 'f';

    snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
         imx581->module_index, facing,
         IMX581_NAME, dev_name(sd->dev));
    // 向v4l2框架注册一个v4l2_subdev。
    ret = v4l2_async_register_subdev_sensor_common(sd);
    if (ret) {
        dev_err(dev, "v4l2 async register subdev failed\n");
        goto err_clean_entity;
    }

    pm_runtime_set_active(dev);
    pm_runtime_enable(dev);
    pm_runtime_idle(dev);

    return 0;

err_clean_entity:
#if defined(CONFIG_MEDIA_CONTROLLER)
    media_entity_cleanup(&sd->entity);
#endif
err_power_off:
    __imx581_power_off(imx581);
err_free_handler:
    v4l2_ctrl_handler_free(&imx581->ctrl_handler);
err_destroy_mutex:
    mutex_destroy(&imx581->mutex);

    return ret;
}

static int imx581_remove(struct i2c_client *client)
{
    struct v4l2_subdev *sd = i2c_get_clientdata(client);
    struct imx581 *imx581 = to_imx581(sd);

    v4l2_async_unregister_subdev(sd);
#if defined(CONFIG_MEDIA_CONTROLLER)
    media_entity_cleanup(&sd->entity);
#endif
    v4l2_ctrl_handler_free(&imx581->ctrl_handler);
    mutex_destroy(&imx581->mutex);

    pm_runtime_disable(&client->dev);
    if (!pm_runtime_status_suspended(&client->dev))
        __imx581_power_off(imx581);
    pm_runtime_set_suspended(&client->dev);

    return 0;
}

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id imx581_of_match[] = {
    { .compatible = "ovti,imx581" },
    {},
};
MODULE_DEVICE_TABLE(of, imx581_of_match);
#endif

static const struct i2c_device_id imx581_match_id[] = {
    { "ovti,imx581", 0 },
    { },
};

static struct i2c_driver imx581_i2c_driver = {
    .driver = {
        .name = IMX581_NAME,
        .pm = &imx581_pm_ops,
        .of_match_table = of_match_ptr(imx581_of_match),
    },
    // 2、当IIC client 驱动匹配成功后就会调用该probe函数。
    .probe		= &imx581_probe,
    .remove		= &imx581_remove,
    .id_table	= imx581_match_id,
};

static int __init sensor_mod_init(void)
{
    // 1、添加一个IIC client，这个IIC client是用来控制模组的。
    return i2c_add_driver(&imx581_i2c_driver);
}

static void __exit sensor_mod_exit(void)
{
    i2c_del_driver(&imx581_i2c_driver);
}

device_initcall_sync(sensor_mod_init);
module_exit(sensor_mod_exit);

MODULE_DESCRIPTION("OmniVision imx581 sensor driver");
MODULE_LICENSE("GPL v2");
